﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement;
using Orchard;
using Orchard.Environment.Extensions;
using Orchard.Security;
using Orchard.Localization;
using Orchard.DisplayManagement;

namespace Downplay.Mechanics.Impulses.Services
{
    [OrchardFeature("Downplay.Mechanics.Impulses")]
    public class ImpulseService : IImpulseService
    {
        private readonly IEnumerable<IImpulseGenerator> _impulseGenerators;
        private readonly IAuthorizationService _authorizationService;

        public ImpulseService(
            IOrchardServices services,
            IEnumerable<IImpulseGenerator> impulseGenerators,
            IAuthorizationService authorizationService,
            IShapeFactory shapeFactory)
        {
            Services = services;
            _impulseGenerators = impulseGenerators;
            _authorizationService = authorizationService;
            T = NullLocalizer.Instance;
            Shape = shapeFactory;
        }

        public IOrchardServices Services { get; set; }
        public Localizer T { get; set; }
        public dynamic Shape { get; set; }

        public IEnumerable<IImpulse> ListImpulses(IContent content, string displayType)
        {
            var context = new ImpulseDisplayContext(){
                Content = content,
                DisplayType = displayType
            };

            foreach (var p in _impulseGenerators)
            {
                p.Generating(context);
            }

            // Check permissions
            List<IImpulse> final = new List<IImpulse>();
            var user = Services.WorkContext.CurrentUser;
            foreach (var impulse in context.Impulses)
            {
                var ok = true;
                // TODO: Check can create required content types
                if (impulse.Permissions.Any(p=>!_authorizationService.TryCheckAccess(p,user,content)))
                {
                    ok = false;
                }
                if (ok)
                {
                    final.Add(impulse);
                }
            }
            context.Impulses = final;

            foreach (var p in _impulseGenerators)
            {
                p.Generated(context);
            }

            return context.Impulses;
        }

        public IImpulse CheckForImpulse(string prefix, string name, int sourceId)
        {
            var content = Services.ContentManager.Get(sourceId);
            var impulse = ListImpulses(content,"").FirstOrDefault(i => i.Name == name && i.Prefix == prefix);
            // TODO: Check permissions here
            return impulse;
        }

        public ImpulseActuationResult ActuateImpulse(ImpulseContext context)
        {
            // Check permissions
            if (!context.Impulse.Permissions.Any(p => Services.Authorizer.Authorize(p, context.SourceContent, T("Unable to perform action"))))
            {
                return ImpulseActuationResult.NotAuthorized;
            }
            foreach (var handle in _impulseGenerators)
            {
                handle.Actuating(context);
            }
            if (context.Actuated)
            {
                foreach (var handle in _impulseGenerators)
                {
                    handle.Actuated(context);
                }
                return ImpulseActuationResult.Ok;
            }
            else
            {
                return ImpulseActuationResult.Failed;
            }
        }

        public IEnumerable<dynamic> BuildImpulseShapes(IContent content, string displayType)
        {
            var impulses = ListImpulses(content, displayType);
            foreach (var impulse in impulses)
            {
                yield return Shape.Impulse(ContentItem: content, Impulse: impulse);
            }
        }
    }
}